from twisted.internet import protocol, defer, reactor
from twisted.internet.task import LoopingCall
from twisted.protocols import basic
import re
import time

from franticfallacy.formatting import *

try:
	set
except NameError:
	from sets import Set as set
	
CONSTATE_NAME, CONSTATE_PWD, CONSTATE_ROLE, CONSTATE_MAIN = range(0,4)

TIMEOUTTIME = 1800

class ChatProtocol(basic.LineReceiver):
	state = CONSTATE_NAME
	# 0: waiting for nickname
	# 1: waiting for password
	# 2: logged in
	new = 0
	
	nickname = None
	character = None
	
	def connectionMade(self):
		#welcome and prompt for name or new
		self.message( MSG_SYSTEM , self.factory.motd )
		#self.message( MSG_SYS_EVENT , 'Login: (\'new\' for new)' )
		self.message( MSG_SYS_EVENT , 'Enter name:' )
		
	def connectionLost(self, reason):
		self.factory.unregister(self.nickname, self)
		self.character.quit()
	
	def lineReceived(self, line):
		if self.state == CONSTATE_NAME:		#receiving name
			#if line == 'new':
			#else:
			self.nickname = line
			if re.match(r'\A[\w!"$-.:-@[-`{-~]{1,15}\Z', self.nickname) is None or self.nickname.lower() in ('new', 'all', 'self'):
				self.message( MSG_SYS_ERR , 'Invalid name.' )
			elif self.factory.register(self.nickname, self):
				self.character = self.factory.world.newPlayer(self)
				self.message( MSG_SYS_INFO , 'Choose a character role: %s' % self.factory.world.roleList() )
				self.state = CONSTATE_ROLE
			else:
				self.message( MSG_SYS_ERR , 'Name in use.' )
		elif self.state == CONSTATE_PWD:	#receiving password
			state = CONSTATE_NAME #not yet implemented, so get out
		elif self.state == CONSTATE_ROLE:	#choosing character role
			if self.factory.world.assignRole(self.character, line):
				self.message( MSG_SYS_INFO , 'Welcome!' )
				self.state = CONSTATE_MAIN
				self.factory.world.defaultZone.takeCreature(self.character)
				self.character.doCommand('%slook' % self.character.cmdmode)
			else:
				self.message( MSG_SYS_ERR , 'Invalid role. Choose: %s'  % self.factory.world.roleList() )
		elif self.state == CONSTATE_MAIN:	#main logged in
			if line.startswith('/'):	#server command
				command, _, arg = line[1:].partition(' ')
				func = self.commands.get(command, None)
				if func is None:
					self.message( MSG_SYS_ERR , 'Invalid command \'%s\'' % command )
				else:
					func(self, arg)
				
			else:						#game command, send to character
				self.character.doCommand(line)
	def message(self, type, line, creature = None):

		if type == MSG_SYSTEM:
			line = colstr( MAGENTA, line )
		elif type == MSG_SYS_INFO:
			line = colstr( YELLOW, line )
		elif type == MSG_SYS_EVENT:
			line = colstr( GREEN, line )
		elif type == MSG_SYS_ERR:
			line = colstr( RED, line )
		elif type == MSG_CHAT:
			line = '%s %s' % (colstr( creature is self.character and CYAN or YELLOW, '<%s>' % creature.name), line)
		elif type == MSG_EMOTE:
			line = colstr( YELLOW, '<%s %s>' % (creature.name, line))
		elif type == MSG_GAME_INFO:
			line = colstr( YELLOW, line )
		elif type == MSG_GAME_EVENT:
			line = colstr( GREEN, line )
			if creature is self.character:
				line = colstr( BOLD, line.replace(creature.name, 'You').replace('is', 'are') )
		elif type == MSG_GAME_ERR:
			line = colstr( RED, line )
		self.sendLine(line)
		
	def command_quit(self, arguments):
		self.message( MSG_SYSTEM , 'Bye!' )
		self.transport.loseConnection()
	def command_time(self, arguments):
		self.message( MSG_SYS_INFO , 'System time: %s' % time.asctime() )
	def command_cmdmode(self, arguments):
		if arguments:
			self.character.cmdmode = arguments
			self.message( MSG_SYS_EVENT , 'Set game command prefix to \'%s\'.' % arguments )
		else:
			self.character.cmdmode = ''
			self.message( MSG_SYS_EVENT , 'Cleared game command prefix.')
	def command_help(self, arguments):
		self.message( MSG_SYS_INFO , 'Available server commands: %s' % ' '.join(self.commands) )
		self.message( MSG_SYS_INFO , 'For game commands see \'%shelp\'' % self.character.cmdmode)
		
	commands = {'quit': command_quit, 'time': command_time, 'cmdmode': command_cmdmode, 'help': command_help, '?': command_help}
		
class ChatFactory(protocol.ServerFactory):
	protocol = ChatProtocol
	def __init__(self):
		self.active_clients = set()
		self.illegal_names = set()
		self.nickname_map = {}
		self.world = None
		self.motd = ''
	def register(self, nickname, listener):
		if nickname.lower() in self.nickname_map:
			return False
		self.active_clients.add(listener)
		self.nickname_map[nickname.lower()] = listener
		self.sysMessage(MSG_SYSTEM, '%s connected.' % nickname)
		return True
	def unregister(self, nickname, listener):
		self.active_clients.remove(listener)
		del self.nickname_map[nickname.lower()]
		self.sysMessage(MSG_SYSTEM, '%s disconnected.' % nickname)
	def sysMessage(self, type, message):
		for client in self.active_clients:
			client.message(type, message)